package cn.zxf.note.note.stats;

import cn.zxf.note.note.review.NoteReviewStatusEnum;
import cn.zxf.note.note.stats.dto.KVStatsDto;
import cn.zxf.note.note.stats.dto.StatsDayDto;
import cn.zxf.note.note.stats.dto.TotalStatsDto;
import com.github.zengxf.common.utils.ListUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.stream.Stream;

/**
 * Created by zengxf on 2019/9/6.
 */
@Component
public class NoteStatsService {

    @Autowired
    private NoteStatsDao dao;

    public List<TotalStatsDto> statsTotal(Integer userId) {
        Map<String, String> map = Map.of(
                NoteReviewStatusEnum.INITIAL.code.toString(), "未复习",
                NoteReviewStatusEnum.REVIEWED.code.toString(), "已复习"
        );
        Integer createTotal = dao.statsCreateTotal(userId);
        List<KVStatsDto> list = dao.statsReviewTotal(userId);

        List<TotalStatsDto> dtoList = new ArrayList<>();
        dtoList.add(new TotalStatsDto("总创建数", createTotal));
        list.forEach(dto -> {
            TotalStatsDto statsDto = new TotalStatsDto(map.get(dto.getName()), dto.getValue());
            dtoList.add(statsDto);
        });
        return dtoList;
    }

    public List<StatsDayDto> statsEveryDay(Integer userId) {
        LocalDate start = LocalDate.now().minusMonths(1);
        LocalDate end = LocalDate.now().plusMonths(1);
        LocalDateTime[] arr = new LocalDateTime[]{
                LocalDateTime.of(start, LocalTime.MIN),
                LocalDateTime.of(end, LocalTime.MAX)
        };
        List<KVStatsDto> createSoList = dao.statsCreateNote(userId, arr);
        List<KVStatsDto> waitReviewSoList = dao.statsActualReview(userId, NoteReviewStatusEnum.INITIAL, arr);
        List<KVStatsDto> reviewedSoList = dao.statsActualReview(userId, NoteReviewStatusEnum.REVIEWED, arr);
        List<KVStatsDto> planSoList = dao.statsPlanReview(userId, arr);
        return this.fill(start, end, createSoList, waitReviewSoList, reviewedSoList, planSoList);
    }

    private List<StatsDayDto> fill(
            LocalDate start, LocalDate end,
            List<KVStatsDto> createSoList,
            List<KVStatsDto> waitReviewSoList,
            List<KVStatsDto> reviewedSoList,
            List<KVStatsDto> planSoList
    ) {
        List<StatsDayDto> list = new ArrayList<>();
        Map<String, KVStatsDto> createMap = ListUtils.toMap(createSoList, KVStatsDto::getName);
        Map<String, KVStatsDto> waitReviewMap = ListUtils.toMap(waitReviewSoList, KVStatsDto::getName);
        Map<String, KVStatsDto> reviewedMap = ListUtils.toMap(reviewedSoList, KVStatsDto::getName);
        Map<String, KVStatsDto> planMap = ListUtils.toMap(planSoList, KVStatsDto::getName);
        Stream.iterate(start, date -> !date.isAfter(end), date -> date.plusDays(1))
                .forEach(date -> {
                    String key = date.toString();
                    StatsDayDto dto = new StatsDayDto();
                    dto.setName(key);
                    this.fill(createMap, key, dto::setCreateValue);
                    this.fill(waitReviewMap, key, dto::setWaitReviewValue);
                    this.fill(reviewedMap, key, dto::setReviewedValue);
                    this.fill(planMap, key, dto::setPlanReviewValue);
                    list.add(dto);
                });
        return list;
    }

    private void fill(Map<String, KVStatsDto> map, String key, Consumer<Integer> consumer) {
        Optional.ofNullable(map.get(key))
                .map(KVStatsDto::getValue)
                .ifPresent(consumer);
    }

}
